/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.unifor.sd.bolsa.servidor.impl;

import br.unifor.sd.bolsa.interfaces.MessageListener;
import br.unifor.sd.bolsa.interfaces.ServidorInterface;
import br.unifor.sd.bolsa.util.Colecao;
import br.unifor.sd.bolsa.util.Dialeto;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Pedro
 */
public class ServidorImplTCP implements ServidorInterface {

    /**
     * Implementação de listener para notificar tela ao chegar uma nova mensagem.
     */
    private List<MessageListener> listeners;
    /**
     * Objeto socket lado servidor.
     */
    private ServerSocket socket;
    /**
     * Flag para indicar que o servidor deve continuar ligado.
     */
    private boolean ligado;

    private Colecao colecao;

    private List <Socket> socketsAbertos;

    @SuppressWarnings("empty-statement")
    public ServidorImplTCP() throws IOException {
        ligado = Boolean.TRUE;
        listeners = new ArrayList<MessageListener>();
        colecao = new Colecao();
        colecao.popularRandomico();
        socketsAbertos = new ArrayList<Socket>();
    }

    /**
     * Implementação do iniciar servidor em TCP
     * @param porta Porta a ser utilizada.
     * @throws java.io.IOException
     */
    public void iniciar(int porta) throws IOException {
        socket = new ServerSocket(porta);
    }

    /**
     * Ação de stop no servidor.
     * @throws java.io.IOException
     */
    public void parar() throws IOException {
        socket.close();
        ligado = Boolean.FALSE;
    }

    public void escutar() {
        Socket socketFilho;
        do {
            try {
                socketFilho = socket.accept();
                socketsAbertos.add(socketFilho);
                new TcpThreadSocket(socketFilho)
                {

                    @Override
                    public void run(){
                        try {
                            byte[] b = new byte[1024];
                            InputStream input = this.socket.getInputStream();
                            OutputStream output = this.socket.getOutputStream();
                            int bytesLidos = 0;
                            String oQueChegou = "";
                            String oQueSaiu = "";
                            while((bytesLidos = input.read(b))!=-1){
                                oQueChegou = new String(b, 0,bytesLidos);
                                //TODO: Tratar chegar Comprar ou vender? 
                                message(System.getProperty("line.separator")+"Chegou isso: "+System.getProperty("line.separator")+oQueChegou+System.getProperty("line.separator"));
                                tratarSaida(oQueChegou);
                                // Sempre responder com lista Completa de ações.
                                oQueSaiu = Dialeto.listaDeAcoesToString(colecao.getLista());
                                message(System.getProperty("line.separator")+"O que saiu:"+System.getProperty("line.separator")+ oQueSaiu);
                                notificarTodos(oQueSaiu);
                                
                                
                            }
                        } catch (IOException ex) {
                            Logger.getLogger(ServidorImplTCP.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

                    private void notificarTodos(String oQueSaiu) {
                        for(int i=0;i<socketsAbertos.size();i++){
                            try {
                                socketsAbertos.get(i).getOutputStream().write(oQueSaiu.getBytes());
                                 socketsAbertos.get(i).getOutputStream().flush();
                            } catch (IOException ex) {
                                Logger.getLogger(ServidorImplTCP.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }

                    private void tratarSaida(String oQueChegou) {
                        String[] split = oQueChegou.split("#");
                        String operacao = split[0];
                        
                        if(operacao.equals("comprar")){
                            int acaoId = Integer.parseInt(split[1]);
                            String dono = split[2];
                            colecao.mudarDono(acaoId,dono);
                        }else if(operacao.equals("comprarValor")){
                            int acaoId = Integer.parseInt(split[1]);
                            String dono = split[2];
                            Double valor = Double.parseDouble(split[3]);
                            colecao.mudarDonoValor(acaoId,dono,valor);
                        }else if(operacao.equals("vender")){

                        }else{

                        }
                    }
                }.start();
            } catch (IOException ex) {
                Logger.getLogger(ServidorImplTCP.class.getName()).log(Level.SEVERE, null, ex);
            }
        } while (ligado);
    }

    public void addListener(MessageListener listener){
        listeners.add(listener);
    }

    private void message(String msg)
    {
        for(int i=0;i<listeners.size();i++){
            listeners.get(i).onMessage(msg);
        }
    }
}
